
/*
 * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
 *
 * (b)  If this Sample Code is distributed as part of the Display PostScript
 *	System Software Development Kit from Adobe Systems Incorporated,
 *	then this copy is designated as Development Software and its use is
 *	subject to the terms of the License Agreement attached to such Kit.
 *
 * (c)  If this Sample Code is distributed independently, then the following
 *	terms apply:
 *
 * (d)  This file may be freely copied and redistributed as long as:
 *	1) Parts (a), (d), (e) and (f) continue to be included in the file,
 *	2) If the file has been modified in any way, a notice of such
 *      modification is conspicuously indicated.
 *
 * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
 *	Adobe Systems Incorporated.
 * 
 * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
 *	CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
 *	AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
 *	ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
 *	OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
 *	WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
 *	WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
 *	DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
 *	FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
 *	OF THIRD PARTY RIGHTS.
 */

/*
 *	ScrollApp.m
 *
 *	This subclass of the application class performs the global
 *	setup needed for the Scrolling application. The drawing
 *	window is created.
 *
 *	Version:	2.0
 *	Author:	Ken Anderson, Ken Fromm
 *	History:
 *			03-07-91		Added this comment.
 */

#import "ScrollApp.h"
#import "DocView.h"
#import "DrawingView.h"
#import "DrawingViewWraps.h"
#import "EpsfParser.h"
#import <objc/hashtable.h>		/* for NXCopyStringBuffer() */
#import <appkit/Button.h>
#import <appkit/Matrix.h>
#import <appkit/OpenPanel.h>
#import <appkit/ScrollView.h>
#import <appkit/Window.h>
#import <appkit/nextstd.h>
#import <sys/param.h>
#import <string.h>

static NXRect			windowRect = {150, 184, 550, 600};

@implementation ScrollApp

/*
*	Allocate the memory for the user path description buffers. Create the
*	window for drawing the image.
*/
+ new
{
	self = [super new];

	NX_MALLOC(drawBuffer.pts, float, PTS_UPATH_BUFFER);
	NX_MALLOC(drawBuffer.ops, char, OPS_UPATH_BUFFER);

	windowBacking = NX_RETAINED;

	readerId = [EpsfParser  new];

	[self  createWindow:&windowRect];

	return self;
}

/*
*	Create the drawing window and place a scrollview as the content view.
*	A DrawingView instance is placed as the DocView of the ScrollView.
*/
- createWindow:(NXRect *) winRect
{
	NXRect	tempRect;

	windowId = [Window newContent:winRect
			style:NX_TITLEDSTYLE
			backing:windowBacking
			buttonMask:NX_RESIZEBUTTONMASK
			defer:NO];

	[Window  getContentRect:&tempRect  forFrameRect:winRect  style:NX_TITLEDSTYLE];
	scrollviewId = [ScrollView newFrame:&tempRect];
	[scrollviewId setBorderType:SCROLLVIEW_BORDER];

	drawingviewId = [[[DrawingView  newFrame:&tempRect]  setClipping:NO]  allocateGState];
	docviewId = [[[[DocView new]  setClipping:NO]  allocateGState]  setScale:1.0];
	[docviewId  setDrawView:drawingviewId];
	[scrollviewId  setDocView:docviewId];

	/*
	*	Important in 2.0 because it eliminates a problem in 2.0 that shifts the halftonephase
	*	over by 1 extra pixel, causing a noticable aberration in a halftone during a scroll.
	*/
	[[[docviewId  superview]  setFlipped:NO]  allocateGState];

	[[windowId setContentView:scrollviewId] free];

	[windowId makeFirstResponder:drawingviewId];
	[windowId setDelegate:self];

	return self;
}

/* The window will free the its subviews. */
- free
{
	if (drawBuffer.pts)
		NX_FREE(drawBuffer.pts);
	if (drawBuffer.ops)
		NX_FREE(drawBuffer.ops);

	[readerId  free];
	[windowId  free];

	return [super free];
}

- setMenuItem:anObject;
{
	menuitemId = anObject;

	return self;
}

- setRedrawButton:anObject
{
	redrawButton = anObject;
	methodsWindow = [redrawButton  window];

	return self;
}

- redrawButton
{
	return redrawButton;
}

- methodsWindow
{
	return methodsWindow;
}

- setStatusMatrix:anObject
{
	statusmatrixId = anObject;

	return self;
}

- getStatusMatrix
{
	return statusmatrixId;
}

- setTimingMatrix:anObject
{
	timingmatrixId = anObject;

	return self;
}

- getTimingMatrix
{
	return timingmatrixId;
}

- setStrokingMatrix:anObject
{
	strokingmatrixId = anObject;

	return self;
}

- getStrokingMatrix
{
	return strokingmatrixId;
}

- setParameterMatrix:anObject
{
	parametermatrixId = anObject;

	return self;
}

- getParameterMatrix
{
	return parametermatrixId;
}

- setTypeOfDrawing:sender
{
	[drawingviewId  setTypeOfDrawing:sender];

	return self;
}

- setSelectivity:sender
{
	[drawingviewId  setSelectivity:sender];

	return self;
}

- setDrawingManner:sender
{
	[drawingviewId  setDrawingManner:sender];

	return self;
}

- setParameterSetting:sender
{
	[drawingviewId  setParameterSetting:sender];

	return self;
}

- setStroking:sender
{
	[drawingviewId  setStroking:sender];

	return self;
}

- setWindowBacking:sender
{
	id		newWindow, oldContentView, tempView;

	char		*windowTitle;

	int		newBacking;

	NXRect	winFrame, contRect;

	if (!runningDrawModal)
	{
		if ([sender selectedRow] == 0)
			newBacking = NX_RETAINED;
		else
			newBacking = NX_BUFFERED;

		if (windowBacking != newBacking)
		{
			[windowId  getFrame:&winFrame];
			[Window  getContentRect:&contRect  forFrameRect:&winFrame
				style:[windowId  style]];
			newWindow = [Window newContent:&contRect
				style:NX_TITLEDSTYLE
				backing:newBacking
				buttonMask:NX_RESIZEBUTTONMASK
				defer:NO];
			[newWindow  setTitle:[windowId  title]];
			[newWindow  display];
			[newWindow makeKeyAndOrderFront:self];

			[windowId  disableDisplay];
			tempView = [View new];
			oldContentView = [windowId  setContentView:tempView];
			[[newWindow setContentView:oldContentView] free];
			[windowId  free];

			windowId = newWindow;
			[windowId makeFirstResponder:drawingviewId];
			[windowId setDelegate:self];

			windowBacking = newBacking;
		}

		if (currentfile)
		{
			[drawingviewId  setFieldsMode:YES];
			[windowId display];
			[windowId makeKeyAndOrderFront:self];
		}
	}

	return self;
}

- showWindow:sender
{
	if (currentfile)
		[windowId makeKeyAndOrderFront:self];
	
	return self;
}

/* This method changes the title of the menu cell according to the
* value of the trace variable.
*/
-setTracing:sender
{
	if (trace == NO)
		[[sender selectedCell] setTitle:"Trace On"];
	else
		[[sender selectedCell] setTitle:"Trace Off"];

	trace = !trace;
	
	return self;
}

- (BOOL) tracing;
{
	return trace;
}

- zoom:sender
{
	[docviewId  zoom:sender];

	return self;
}

- redrawAction:sender
{
	if (!runningDrawModal)
		[redrawButton  performClick:self];
	
	return self;
}

- redraw:sender
{
	NXRect	visRect;
	
	if (!runningDrawModal)
	{
		[drawingviewId  setFieldsMode:YES];
		[drawingviewId  getVisibleRect:&visRect];
		[drawingviewId  display:&visRect :1];
	}

	return self;
}

- displayFields:sender
{
	[drawingviewId  displayFields:sender];
	
	return self;
}

- getDrawingView
{
	return drawingviewId;
}

- getDocument
{
	return docviewId;
}

- (UPath *) getUpathBuffer
{
	return &drawBuffer;
}

/*
 * Called by pressing Load... in the Main menu.
 */
- load:sender
{
	id				openpanelId, tempviewId, clipviewId;

	const char		*file;
 
	static const char *const		doctype[3] = {"ps", "eps", NULL};
   
   	NXStream		*stream;
 
 	NXPoint			viewPt, windowPt;

 	NXRect			epsfBounds, viewFrame;

	openpanelId = [[OpenPanel new] allowMultipleFiles:NO];

	if ([openpanelId runModalForTypes:doctype])
	{
		file = [openpanelId filename];
		if (!currentfile || strcmp(file, currentfile))
		{
			stream = NXMapFile(file, NX_READONLY);
			if (stream)
			{
				tempviewId = [View new];
				[windowId  setContentView:tempviewId];
				[self setName:file withParsing:YES];
				[windowId display];
				[windowId makeKeyAndOrderFront:self];
				NXPing();
				[[windowId  setContentView:scrollviewId]  free];

				if ([readerId  readPSFromStream:stream])
				{
					[docviewId  scaleView:drawingviewId  withScale:1.0];
					[docviewId  setScale:1.0];
					[[docviewId  zoomControl]  selectCellWithTag:100];				

					[readerId  getBounds:&epsfBounds];
					[drawingviewId  setDrawOrigin:&epsfBounds.origin];
					[drawingviewId  sizeTo:epsfBounds.size.width  :epsfBounds.size.height];

					[self setName:file withParsing:NO];
					if (currentfile)
						NX_FREE(currentfile);
					currentfile = NXCopyStringBuffer(file);

					[windowId disableDisplay];
						[docviewId  placeView:drawingviewId];

						/* Scroll center of image to center of window. */
						[docviewId  getFrame:&viewFrame];
						viewPt.x = viewFrame.size.width/2;
						viewPt.y = viewFrame.size.height/2;
						[drawingviewId  convertPoint:&viewPt
								fromView:docviewId];

						[scrollviewId  getFrame:&viewFrame];
						windowPt.x = viewFrame.size.width/2;
						windowPt.y = viewFrame.size.height/2;
						[scrollviewId  convertPoint:&windowPt  toView:nil];

						[docviewId  scrollPoint:&viewPt 
								inView:drawingviewId  to:&windowPt];
					[windowId reenableDisplay];

					[drawingviewId  setFieldsMode:YES];
					[windowId display];
				}
				else
				{
					[self setName:currentfile withParsing:NO];
					[windowId  display];
				}
	
				NXCloseMemory(stream, NX_FREEBUFFER);
			}
			else
				NXRunAlertPanel("Load File", "Invalid File.  Cannot open.", 
					"OK", NULL, NULL);
		}
	}

	return self;
}

/*
 * Updates the name and directory of the document.
 */
- setName:(const char *)filename withParsing:(BOOL) flag
{
	int		len = 0;

	char		title[MAXPATHLEN+5];
	
	char		*simple_filename;

	if (filename && *filename)
	{
		if (flag)
			strcpy(title, "parsing:");
		else
			title[0] = 0;

		simple_filename = strrchr(filename, '/');
		if (simple_filename)
		{
			len = strlen(simple_filename);
			simple_filename++;
			strcat(title, simple_filename);
			strcat(title, " \320 ");			/* \320 is a "long dash" */
			strcatn(title, filename, strlen(filename) - len);
		}
		else
			strcat(title, filename);	

		[windowId setTitle:title];
		[menuitemId  setEnabled:YES];
	}
	else
		[windowId setTitle:"Scrolling"];

	return self;
}

/*
 * Resizes the doc view and repositions the drawing view inside the doc view.
 */
- windowDidResize:sender
{
	[docviewId  placeView:drawingviewId];

	return self;
}

- (int) runDrawModalSession:(NXModalSession *) session
{
	int			returnCode1, returnCode2;

	NXPoint		pt;
	
	NXEvent		*anEvent;

	runningDrawModal = YES;
	returnCode1 = NX_RUNCONTINUES;
	while (anEvent = [NXApp  getNextEvent:NX_MOUSEDOWNMASK  waitFor:0 
		threshold:NX_RUNMODALTHRESHOLD])
	{
		if (anEvent->window == [methodsWindow windowNum])
		{
			redrawButton = [NXApp redrawButton];
			pt = anEvent->location;
			[[redrawButton superview] convertPoint:&pt fromView:nil];
			if ([redrawButton  hitTest:&pt] == redrawButton)
			{
				[redrawButton  performClick:self];
				returnCode1 = NX_RUNABORTED;
			}
		}
	}
	
	returnCode2 =  [self  runModalSession:session];
	runningDrawModal = NO;
	
	if (returnCode1 == NX_RUNABORTED)
		return returnCode1;
	else
		return returnCode2;
}

@end

